///**
//Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//*/
//package bftsmart.demo.microbenchmarks;
//
//import bftsmart.consensus.app.BatchAppResultImpl;
//import bftsmart.tom.MessageContext;
//import bftsmart.tom.ReplyContextMessage;
//import bftsmart.tom.ServiceReplica;
//import bftsmart.tom.server.defaultservices.DefaultRecoverable;
//import bftsmart.tom.util.Storage;
//
//import java.util.List;
//
///**
// * Simple server that just acknowledge the reception of a request.
// */
//public class LatencyServer extends DefaultRecoverable{
//
//    private int interval;
//    private int replySize;
//
//    private int iterations = 0;
//    private Storage totalLatency = null;
//    private Storage consensusLatency = null;
//    private Storage preConsLatency = null;
//    private Storage posConsLatency = null;
//    private Storage proposeLatency = null;
//    private Storage writeLatency = null;
//    private Storage acceptLatency = null;
//    private ServiceReplica replica;
//
//    public LatencyServer(int id, int interval, int replySize) {
//
//        this.interval = interval;
//        this.replySize = replySize;
//
//        totalLatency = new Storage(interval);
//        consensusLatency = new Storage(interval);
//        preConsLatency = new Storage(interval);
//        posConsLatency = new Storage(interval);
//        proposeLatency = new Storage(interval);
//        writeLatency = new Storage(interval);
//        acceptLatency = new Storage(interval);
//
//    	replica = new ServiceReplica(id, this, this);
//    }
//
//    @Override
//    public BatchAppResultImpl preComputeAppHash(byte[][] commands) {
//        return null;
//    }
//
//    @Override
//    public List<byte[]> updateAppResponses(List<byte[]> asyncResponseLinkedList, byte[] commonHash, boolean isConsistent) {
//        return null;
//    }
//
//    @Override
//    public void preComputeAppCommit(String batchId) {
//
//    }
//
//    @Override
//    public void preComputeAppRollback(String batchId) {
//
//    }
//
//    @Override
//    public byte[] appExecuteUnordered(byte[] command, MessageContext msgCtx) {
//        return execute(command,msgCtx);
//    }
//
//    @Override
//    public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus) {
//        byte[][] replies = new byte[commands.length][];
//
//        for (int i = 0; i < commands.length; i++) {
//
//            replies[i] = execute(commands[i],msgCtxs[i]);
//
//        }
//
//        return replies;
//    }
//
//    @Override
//    public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus, List<ReplyContextMessage> replyContextMessages) {
//        return appExecuteBatch(commands, msgCtxs, fromConsensus);
//    }
//
//    public byte[] execute(byte[] command, MessageContext msgCtx) {
//        boolean readOnly = false;
//
//        iterations++;
//
//        if (msgCtx != null && msgCtx.getFirstInBatch() != null) {
//
//
//            readOnly = msgCtx.readOnly;
//
//            msgCtx.getFirstInBatch().executedTime = System.nanoTime();
//
//            totalLatency.store(msgCtx.getFirstInBatch().executedTime - msgCtx.getFirstInBatch().receptionTime);
//
//            if (readOnly == false) {
//
//                consensusLatency.store(msgCtx.getFirstInBatch().decisionTime - msgCtx.getFirstInBatch().consensusStartTime);
//                long temp = msgCtx.getFirstInBatch().consensusStartTime - msgCtx.getFirstInBatch().receptionTime;
//                preConsLatency.store(temp > 0 ? temp : 0);
//                posConsLatency.store(msgCtx.getFirstInBatch().executedTime - msgCtx.getFirstInBatch().decisionTime);
//                proposeLatency.store(msgCtx.getFirstInBatch().writeSentTime - msgCtx.getFirstInBatch().consensusStartTime);
//                writeLatency.store(msgCtx.getFirstInBatch().acceptSentTime - msgCtx.getFirstInBatch().writeSentTime);
//                acceptLatency.store(msgCtx.getFirstInBatch().decisionTime - msgCtx.getFirstInBatch().acceptSentTime);
//
//
//            } else {
//
//
//                consensusLatency.store(0);
//                preConsLatency.store(0);
//                posConsLatency.store(0);
//                proposeLatency.store(0);
//                writeLatency.store(0);
//                acceptLatency.store(0);
//
//
//            }
//
//        } else {
//
//
//                consensusLatency.store(0);
//                preConsLatency.store(0);
//                posConsLatency.store(0);
//                proposeLatency.store(0);
//                writeLatency.store(0);
//                acceptLatency.store(0);
//
//
//        }
//
//        if(iterations % interval == 0) {
//            System.out.println("--- Measurements after "+ iterations+" ops ("+interval+" samples) ---");
//            System.out.println("Total latency = " + totalLatency.getAverage(false) / 1000 + " (+/- "+ (long)totalLatency.getDP(false) / 1000 +") us ");
//            totalLatency.reset();
//            System.out.println("Consensus latency = " + consensusLatency.getAverage(false) / 1000 + " (+/- "+ (long)consensusLatency.getDP(false) / 1000 +") us ");
//            consensusLatency.reset();
//            System.out.println("Pre-consensus latency = " + preConsLatency.getAverage(false) / 1000 + " (+/- "+ (long)preConsLatency.getDP(false) / 1000 +") us ");
//            preConsLatency.reset();
//            System.out.println("Pos-consensus latency = " + posConsLatency.getAverage(false) / 1000 + " (+/- "+ (long)posConsLatency.getDP(false) / 1000 +") us ");
//            posConsLatency.reset();
//            System.out.println("Propose latency = " + proposeLatency.getAverage(false) / 1000 + " (+/- "+ (long)proposeLatency.getDP(false) / 1000 +") us ");
//            proposeLatency.reset();
//            System.out.println("Write latency = " + writeLatency.getAverage(false) / 1000 + " (+/- "+ (long)writeLatency.getDP(false) / 1000 +") us ");
//            writeLatency.reset();
//            System.out.println("Accept latency = " + acceptLatency.getAverage(false) / 1000 + " (+/- "+ (long)acceptLatency.getDP(false) / 1000 +") us ");
//            acceptLatency.reset();
//        }
//
//        return new byte[replySize];
//    }
//
//    public static void main(String[] args){
//        if(args.length < 3) {
//            System.out.println("Use: java ...LatencyServer <processId> <measurement interval> <reply size>");
//            System.exit(-1);
//        }
//
//        int processId = Integer.parseInt(args[0]);
//        int interval = Integer.parseInt(args[1]);
//        int replySize = Integer.parseInt(args[2]);
//
//        new LatencyServer(processId,interval,replySize);
//    }
//
//    @Override
//    public void installSnapshot(byte[] state) {
//
//    }
//
//    @Override
//    public byte[] getSnapshot() {
//        return new byte[0];
//    }
//
//}
